/* Zatok - язык программирования текстовых игр
 * (С) 2010 - 2012 Меркулов Матвей Юрьевич
 * Код лицензирован под лицензией GNU LGPL
 * Вы можете прочитать текст лицензии по адресу:
 * http://www.gnu.org/copyleft/lesser.html
 * или прочитать русский перевод по адресу:
 * http://ru.wikisource.org/wiki/GNU_Lesser_General_Public_License
 */

package parser;

import base.CGraphics;
import base.context.CCommand;
import base.module.CModule;
import base.userfunction.CUserFunction;
import base.userfunction.CUserFunctionID;
import base.value.userobject.CBaseData;
import base.value.userobject.CUserObject;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.Map;

public class CInheritance {
	private static LinkedList<CInheritance> Inheritances = new LinkedList<CInheritance>();
	private static HashMap<CUserObject,LinkedList<CUserObject>> Structure;
	private static HashSet<CUserObject> EncounteredObjects;
	public CUserObject Parent;
	public CUserObject Child;
	public boolean AddDescription = true;
	public boolean AddActions = true;



	@SuppressWarnings( "LeakingThisInConstructor" )
	public CInheritance( CUserObject NewParent, CUserObject NewChild  ) {
		Parent = NewParent;
		Child = NewChild;
		Inheritances.add( this );
	}



	public static void ApplyInheritances() {

		// проверка на кольца наследования

		Structure = new HashMap<CUserObject,LinkedList<CUserObject>>();
		HashSet<CUserObject> Objects = new HashSet<CUserObject>();
		for( CInheritance Inheritance : Inheritances ) {
			LinkedList<CUserObject> List = Structure.get( Inheritance.Parent );
			if( List == null ) {
				List = new LinkedList<CUserObject>();
				Structure.put( Inheritance.Parent, List );
			}
			Objects.add( Inheritance.Parent );
			List.add( Inheritance.Child );
		}

		for( CUserObject Object : Structure.keySet() ) {
			if( !Objects.contains( Object ) ) continue;
			EncounteredObjects = new HashSet<CUserObject>();
			CheckForLoops( Object );
		}

		// сортировка списка наследований

		while (true) {
			boolean Collision = false;

			HashSet<CUserObject> Parents = new HashSet<CUserObject>();
			ListIterator<CInheritance> Iterator = Inheritances.listIterator();
			while( Iterator.hasNext() ) {
				CInheritance Inheritance = Iterator.next();
				Parents.add( Inheritance.Parent );
				if( Parents.contains( Inheritance.Child ) ) {
					Iterator.remove();
					Inheritances.addFirst( Inheritance );
					Collision = true;
					break;
				}
			}

			if( !Collision ) break;
		}

		// применение наследований

		for( CInheritance Inheritance : Inheritances ) {
			CBaseData ParentBaseData = Inheritance.Parent.BaseData;
			CBaseData ChildBaseData = Inheritance.Child.BaseData;

			Iterator<CModule> Iterator = ParentBaseData.Initialization.descendingIterator();
			while( Iterator.hasNext() ) ChildBaseData.Initialization.addFirst( Iterator.next() );

			Iterator<CCommand> Iterator2 = ParentBaseData.Commands.descendingIterator();
			while( Iterator2.hasNext() ) ChildBaseData.Commands.addFirst( Iterator2.next() );
			
			for( Map.Entry<CUserFunctionID, CUserFunction> Entry : ParentBaseData.Functions.entrySet() ) {
				if( !ChildBaseData.Functions.containsKey( Entry.getKey() ) ) ChildBaseData.Functions.put( Entry.getKey(), Entry.getValue() );
			}
		}
	}



	private static void CheckForLoops( CUserObject Object ) {
		if( EncounteredObjects.contains( Object ) ) CGraphics.Error( "Встречено кольцо наследований на объекте \"" + Object.BaseData.Name[ 0 ] + "\"" );
		EncounteredObjects.add( Object );
		LinkedList<CUserObject> List = Structure.get( Object );
		if( List == null ) return;
		for( CUserObject ChildObject : List ) {
			CheckForLoops( ChildObject );
		}
	}
}
